<template>
  <el-dialog
    v-model="visible"
    :title="title"
    :width="width"
    :fullscreen="fullscreen"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    :before-close="handleBeforeClose"
    append-to-body
    class="form-dialog"
    :class="dialogClass"
  >
    <div class="form-dialog__content">
      <el-form
        ref="formRef"
        :model="formData"
        :rules="formRules"
        :label-width="labelWidth"
        :label-position="labelPosition"
        :size="size"
        :disabled="submitting"
        class="form-dialog__form"
      >
        <el-row :gutter="gutter">
          <template v-for="field in visibleFields" :key="field.prop">
            <el-col :span="field.span || defaultSpan" :xs="field.xs" :sm="field.sm" :md="field.md" :lg="field.lg" :xl="field.xl">
              <el-form-item
                :label="field.label"
                :prop="field.prop"
                :required="field.required"
                :rules="field.rules"
                :class="field.itemClass"
              >
                <!-- 输入框 -->
                <el-input
                  v-if="field.type === 'input'"
                  v-model="formData[field.prop]"
                  :type="field.inputType || 'text'"
                  :placeholder="field.placeholder || `请输入${field.label}`"
                  :clearable="field.clearable !== false"
                  :show-password="field.showPassword"
                  :maxlength="field.maxlength"
                  :show-word-limit="field.showWordLimit"
                  v-bind="field.props"
                />
                
                <!-- 文本域 -->
                <el-input
                  v-else-if="field.type === 'textarea'"
                  v-model="formData[field.prop]"
                  type="textarea"
                  :placeholder="field.placeholder || `请输入${field.label}`"
                  :rows="field.rows || 3"
                  :maxlength="field.maxlength"
                  :show-word-limit="field.showWordLimit"
                  v-bind="field.props"
                />
                
                <!-- 数字输入框 -->
                <el-input-number
                  v-else-if="field.type === 'number'"
                  v-model="formData[field.prop]"
                  :min="field.min"
                  :max="field.max"
                  :step="field.step"
                  :precision="field.precision"
                  :placeholder="field.placeholder"
                  class="w-full"
                  v-bind="field.props"
                />
                
                <!-- 选择器 -->
                <el-select
                  v-else-if="field.type === 'select'"
                  v-model="formData[field.prop]"
                  :placeholder="field.placeholder || `请选择${field.label}`"
                  :clearable="field.clearable !== false"
                  :multiple="field.multiple"
                  :filterable="field.filterable"
                  class="w-full"
                  v-bind="field.props"
                >
                  <el-option
                    v-for="option in field.options"
                    :key="option.value"
                    :label="option.label"
                    :value="option.value"
                    :disabled="option.disabled"
                  />
                </el-select>
                
                <!-- 级联选择器 -->
                <el-cascader
                  v-else-if="field.type === 'cascader'"
                  v-model="formData[field.prop]"
                  :options="field.options"
                  :placeholder="field.placeholder || `请选择${field.label}`"
                  :clearable="field.clearable !== false"
                  :filterable="field.filterable"
                  class="w-full"
                  v-bind="field.props"
                />
                
                <!-- 日期选择器 -->
                <el-date-picker
                  v-else-if="field.type === 'date'"
                  v-model="formData[field.prop]"
                  :type="field.dateType || 'date'"
                  :placeholder="field.placeholder || `请选择${field.label}`"
                  :clearable="field.clearable !== false"
                  :format="field.format"
                  :value-format="field.valueFormat"
                  class="w-full"
                  v-bind="field.props"
                />
                
                <!-- 时间选择器 -->
                <el-time-picker
                  v-else-if="field.type === 'time'"
                  v-model="formData[field.prop]"
                  :placeholder="field.placeholder || `请选择${field.label}`"
                  :clearable="field.clearable !== false"
                  :format="field.format"
                  :value-format="field.valueFormat"
                  class="w-full"
                  v-bind="field.props"
                />
                
                <!-- 单选框组 -->
                <el-radio-group
                  v-else-if="field.type === 'radio'"
                  v-model="formData[field.prop]"
                  :size="field.size"
                  v-bind="field.props"
                >
                  <el-radio
                    v-for="option in field.options"
                    :key="option.value"
                    :label="option.value"
                    :disabled="option.disabled"
                  >
                    {{ option.label }}
                  </el-radio>
                </el-radio-group>
                
                <!-- 复选框组 -->
                <el-checkbox-group
                  v-else-if="field.type === 'checkbox'"
                  v-model="formData[field.prop]"
                  :size="field.size"
                  v-bind="field.props"
                >
                  <el-checkbox
                    v-for="option in field.options"
                    :key="option.value"
                    :label="option.value"
                    :disabled="option.disabled"
                  >
                    {{ option.label }}
                  </el-checkbox>
                </el-checkbox-group>
                
                <!-- 开关 -->
                <el-switch
                  v-else-if="field.type === 'switch'"
                  v-model="formData[field.prop]"
                  :active-value="field.activeValue ?? true"
                  :inactive-value="field.inactiveValue ?? false"
                  :active-text="field.activeText"
                  :inactive-text="field.inactiveText"
                  v-bind="field.props"
                />
                
                <!-- 滑块 -->
                <el-slider
                  v-else-if="field.type === 'slider'"
                  v-model="formData[field.prop]"
                  :min="field.min || 0"
                  :max="field.max || 100"
                  :step="field.step || 1"
                  :range="field.range"
                  :show-input="field.showInput"
                  v-bind="field.props"
                />
                
                <!-- 评分 -->
                <el-rate
                  v-else-if="field.type === 'rate'"
                  v-model="formData[field.prop]"
                  :max="field.max || 5"
                  :allow-half="field.allowHalf"
                  :show-text="field.showText"
                  :show-score="field.showScore"
                  v-bind="field.props"
                />
                
                <!-- 颜色选择器 -->
                <el-color-picker
                  v-else-if="field.type === 'color'"
                  v-model="formData[field.prop]"
                  :show-alpha="field.showAlpha"
                  :color-format="field.colorFormat"
                  v-bind="field.props"
                />
                
                <!-- 文件上传 -->
                <FileUpload
                  v-else-if="field.type === 'file'"
                  v-model="formData[field.prop]"
                  :multiple="field.multiple"
                  :limit="field.limit"
                  :max-size="field.maxSize"
                  :accept="field.accept"
                  :business-type="field.businessType"
                  v-bind="field.props"
                />
                
                <!-- 图片上传 -->
                <ImageUpload
                  v-else-if="field.type === 'image'"
                  v-model="formData[field.prop]"
                  :multiple="field.multiple"
                  :limit="field.limit"
                  :max-size="field.maxSize"
                  :business-type="field.businessType"
                  v-bind="field.props"
                />
                
                <!-- 自定义插槽 -->
                <slot
                  v-else-if="field.type === 'slot'"
                  :name="field.slotName || field.prop"
                  :field="field"
                  :value="formData[field.prop]"
                  :setValue="(val: any) => formData[field.prop] = val"
                  :form-data="formData"
                />
                
                <!-- 显示文本 -->
                <span v-else-if="field.type === 'display'" class="form-display-text">
                  {{ formData[field.prop] || field.defaultText || '-' }}
                </span>
                
                <!-- 分隔线 -->
                <el-divider v-else-if="field.type === 'divider'" :content-position="field.contentPosition">
                  {{ field.text }}
                </el-divider>
                
                <!-- 帮助文本 -->
                <div v-if="field.help" class="field-help">
                  <el-icon class="help-icon"><QuestionFilled /></el-icon>
                  <span class="help-text">{{ field.help }}</span>
                </div>
              </el-form-item>
            </el-col>
          </template>
        </el-row>
      </el-form>
      
      <!-- 自定义内容插槽 -->
      <div v-if="$slots.default" class="form-dialog__extra">
        <slot :form-data="formData" :set-field-value="setFieldValue" />
      </div>
    </div>

    <template #footer>
      <div class="form-dialog__footer">
        <el-button @click="handleCancel" :disabled="submitting">
          {{ cancelText }}
        </el-button>
        <LoadingButton
          :text="confirmText"
          :loading-text="submittingText"
          type="primary"
          :loading="submitting"
          @click="handleSubmit"
        />
      </div>
    </template>
  </el-dialog>
</template>

<script setup lang="ts">
import { ref, computed, reactive, watch, nextTick } from 'vue'
import { QuestionFilled } from '@element-plus/icons-vue'
import { FileUpload, ImageUpload, LoadingButton } from '@/components'
import type { FormInstance, FormRules } from 'element-plus'

export interface FormField {
  // 基础属性
  prop: string
  label: string
  type: 'input' | 'textarea' | 'number' | 'select' | 'cascader' | 'date' | 'time' | 
        'radio' | 'checkbox' | 'switch' | 'slider' | 'rate' | 'color' | 
        'file' | 'image' | 'slot' | 'display' | 'divider'
  
  // 布局属性
  span?: number
  xs?: number
  sm?: number
  md?: number
  lg?: number
  xl?: number
  
  // 表单验证
  required?: boolean
  rules?: any[]
  
  // 通用属性
  placeholder?: string
  disabled?: boolean | ((formData: any) => boolean)
  visible?: boolean | ((formData: any) => boolean)
  clearable?: boolean
  props?: Record<string, any>
  itemClass?: string | string[]
  help?: string
  
  // 输入框专用
  inputType?: 'text' | 'password' | 'email' | 'url' | 'tel'
  showPassword?: boolean
  maxlength?: number
  showWordLimit?: boolean
  
  // 文本域专用
  rows?: number
  
  // 数字输入框专用
  min?: number
  max?: number
  step?: number
  precision?: number
  
  // 选择器专用
  options?: Array<{ label: string; value: any; disabled?: boolean }>
  multiple?: boolean
  filterable?: boolean
  
  // 日期/时间选择器专用
  dateType?: 'date' | 'datetime' | 'year' | 'month' | 'week' | 'daterange' | 'datetimerange'
  format?: string
  valueFormat?: string
  
  // 开关专用
  activeValue?: any
  inactiveValue?: any
  activeText?: string
  inactiveText?: string
  
  // 滑块专用
  range?: boolean
  showInput?: boolean
  
  // 评分专用
  allowHalf?: boolean
  showText?: boolean
  showScore?: boolean
  
  // 颜色选择器专用
  showAlpha?: boolean
  colorFormat?: 'hex' | 'rgb' | 'rgba' | 'hsl' | 'hsla'
  
  // 文件上传专用
  limit?: number
  maxSize?: number
  accept?: string
  businessType?: string
  
  // 插槽专用
  slotName?: string
  
  // 显示文本专用
  defaultText?: string
  
  // 分隔线专用
  text?: string
  contentPosition?: 'left' | 'center' | 'right'
  
  // 表单联动
  dependsOn?: string[]
  
  // 组件大小
  size?: 'large' | 'default' | 'small'
}

export interface FormDialogProps {
  modelValue?: boolean
  title?: string
  width?: string | number
  fullscreen?: boolean
  
  // 表单配置
  fields: FormField[]
  formData?: Record<string, any>
  defaultValues?: Record<string, any>
  rules?: FormRules
  
  // 表单样式
  labelWidth?: string | number
  labelPosition?: 'left' | 'right' | 'top'
  size?: 'large' | 'default' | 'small'
  gutter?: number
  defaultSpan?: number
  
  // 状态控制
  submitting?: boolean
  
  // 按钮文本
  confirmText?: string
  cancelText?: string
  submittingText?: string
  
  // 关闭确认
  confirmBeforeClose?: boolean
  closeConfirmText?: string
}

const props = withDefaults(defineProps<FormDialogProps>(), {
  modelValue: false,
  title: '表单',
  width: '600px',
  fullscreen: false,
  formData: () => ({}),
  defaultValues: () => ({}),
  labelWidth: '80px',
  labelPosition: 'right',
  size: 'default',
  gutter: 20,
  defaultSpan: 24,
  submitting: false,
  confirmText: '确定',
  cancelText: '取消',
  submittingText: '提交中...',
  confirmBeforeClose: true,
  closeConfirmText: '确定要关闭吗？未保存的数据将丢失。'
})

const emit = defineEmits<{
  'update:modelValue': [value: boolean]
  'update:formData': [data: Record<string, any>]
  'submit': [data: Record<string, any>]
  'cancel': []
  'close': []
}>()

const formRef = ref<FormInstance>()
const visible = ref(props.modelValue)

// 初始化表单数据
const initFormData = () => {
  const data: Record<string, any> = {}
  
  props.fields.forEach(field => {
    if (field.type === 'divider') return
    
    if (props.formData[field.prop] !== undefined) {
      data[field.prop] = props.formData[field.prop]
    } else if (props.defaultValues[field.prop] !== undefined) {
      data[field.prop] = props.defaultValues[field.prop]
    } else {
      // 设置默认值
      switch (field.type) {
        case 'checkbox':
          data[field.prop] = []
          break
        case 'switch':
          data[field.prop] = field.inactiveValue ?? false
          break
        case 'number':
        case 'slider':
        case 'rate':
          data[field.prop] = field.min ?? 0
          break
        default:
          data[field.prop] = null
      }
    }
  })
  
  return data
}

const formData = reactive(initFormData())

// 对话框样式类
const dialogClass = computed(() => [
  `form-dialog--${props.size}`,
  {
    'form-dialog--fullscreen': props.fullscreen
  }
])

// 表单规则
const formRules = computed(() => {
  const rules: FormRules = { ...props.rules }
  
  // 从字段配置中生成规则
  props.fields.forEach(field => {
    if (field.type === 'divider') return
    
    const fieldRules = []
    
    // 必填规则
    if (field.required) {
      fieldRules.push({
        required: true,
        message: `请${field.type === 'select' || field.type === 'cascader' || field.type === 'date' || field.type === 'time' ? '选择' : '输入'}${field.label}`,
        trigger: ['blur', 'change']
      })
    }
    
    // 自定义规则
    if (field.rules) {
      fieldRules.push(...field.rules)
    }
    
    if (fieldRules.length > 0) {
      rules[field.prop] = fieldRules
    }
  })
  
  return rules
})

// 可见字段
const visibleFields = computed(() => {
  return props.fields.filter(field => {
    if (typeof field.visible === 'function') {
      return field.visible(formData)
    }
    return field.visible !== false
  }).map(field => {
    // 处理禁用状态
    if (typeof field.disabled === 'function') {
      return {
        ...field,
        disabled: field.disabled(formData)
      }
    }
    return field
  })
})

// 监听 modelValue 变化
watch(() => props.modelValue, (val) => {
  visible.value = val
})

// 监听 visible 变化
watch(visible, (val) => {
  emit('update:modelValue', val)
  if (!val) {
    emit('close')
  }
})

// 监听 formData 变化
watch(() => props.formData, (newData) => {
  Object.assign(formData, newData)
}, { deep: true })

// 监听表单数据变化
watch(formData, (newData) => {
  emit('update:formData', newData)
}, { deep: true })

// 设置字段值
const setFieldValue = (prop: string, value: any) => {
  formData[prop] = value
}

// 关闭前确认
const handleBeforeClose = async (done: () => void) => {
  if (props.confirmBeforeClose && !props.submitting) {
    try {
      const { ElMessageBox } = await import('element-plus')
      await ElMessageBox.confirm(
        props.closeConfirmText,
        '确认关闭',
        {
          type: 'warning',
          confirmButtonText: '确定',
          cancelButtonText: '取消'
        }
      )
      done()
    } catch {
      // 用户取消了关闭
    }
  } else {
    done()
  }
}

// 提交表单
const handleSubmit = async () => {
  if (!formRef.value) return
  
  try {
    await formRef.value.validate()
    emit('submit', { ...formData })
  } catch (error) {
    console.error('表单验证失败:', error)
  }
}

// 取消
const handleCancel = () => {
  visible.value = false
  emit('cancel')
}

// 重置表单
const resetForm = () => {
  formRef.value?.resetFields()
  Object.assign(formData, initFormData())
}

// 验证表单
const validateForm = () => {
  return formRef.value?.validate()
}

// 验证指定字段
const validateField = (prop: string) => {
  return formRef.value?.validateField(prop)
}

// 清除验证
const clearValidate = (prop?: string) => {
  formRef.value?.clearValidate(prop)
}

// 暴露方法
defineExpose({
  resetForm,
  validateForm,
  validateField,
  clearValidate,
  setFieldValue,
  getFormData: () => ({ ...formData })
})
</script>

<style scoped>
.form-dialog {
  --el-dialog-padding-primary: 0;
}

.form-dialog__content {
  padding: 20px;
  max-height: 60vh;
  overflow-y: auto;
}

.form-dialog__form {
  width: 100%;
}

.form-dialog__extra {
  margin-top: 20px;
  padding-top: 20px;
  border-top: 1px solid var(--el-border-color-lighter);
}

.form-dialog__footer {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
  padding: 20px;
  border-top: 1px solid var(--el-border-color-lighter);
  background: var(--el-fill-color-lighter);
}

/* 字段帮助信息 */
.field-help {
  display: flex;
  align-items: center;
  margin-top: 4px;
  font-size: 12px;
  color: var(--el-text-color-regular);
}

.help-icon {
  margin-right: 4px;
  font-size: 12px;
  color: var(--el-color-info);
}

.help-text {
  line-height: 1.4;
}

/* 显示文本 */
.form-display-text {
  display: inline-block;
  padding: 8px 0;
  color: var(--el-text-color-primary);
  font-size: 14px;
}

/* 全宽组件 */
.w-full {
  width: 100%;
}

/* 尺寸变体 */
.form-dialog--small .form-dialog__content {
  padding: 16px;
}

.form-dialog--small .form-dialog__footer {
  padding: 16px;
}

.form-dialog--large .form-dialog__content {
  padding: 24px;
}

.form-dialog--large .form-dialog__footer {
  padding: 24px;
}

/* 全屏模式 */
.form-dialog--fullscreen .form-dialog__content {
  max-height: calc(100vh - 120px);
}

/* 响应式设计 */
@media (max-width: 768px) {
  .form-dialog__content {
    padding: 16px;
    max-height: calc(100vh - 120px);
  }
  
  .form-dialog__footer {
    padding: 16px;
    flex-direction: column-reverse;
  }
  
  .form-dialog__footer .el-button {
    width: 100%;
  }
}

/* 表单项间距优化 */
.form-dialog__form :deep(.el-form-item) {
  margin-bottom: 20px;
}

.form-dialog__form :deep(.el-form-item:last-child) {
  margin-bottom: 0;
}

/* 分隔线样式 */
.form-dialog__form :deep(.el-divider) {
  margin: 16px 0;
}

/* 开关组件对齐 */
.form-dialog__form :deep(.el-switch) {
  display: flex;
  align-items: center;
  height: 32px;
}
</style>
